﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Text;
using System.Windows.Forms;

using IronPython.Runtime.Exceptions;

using SPCoder.Autorun;
using SPCoder.Config;
using SPCoder.Context;
using SPCoder.Describer;
using SPCoder.HelperWindows;
using SPCoder.Scripting;
using SPCoder.Utils;
using AutoRunScriptsForm=SPCoder.Autorun.AutoRunScriptsForm;
using SPCoder.Utils.Nodes;
using SPCoder.Windows;
using System.Reflection;
using WeifenLuo.WinFormsUI.Docking;
using FastColoredTextBoxNS;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition;
using SPCoder.Core.Utils;

namespace SPCoder
{
    /// <summary>
    /// SPCoder main form.
    /// </summary>
    /// <author>Damjan Tomic</author>
    public partial class SPCoderForm : Form
    {
        #region Fields
        //private readonly SyntaxDefinitionList Languages = new SyntaxDefinitionList();
        public IronPythonContext MyContext = new IronPythonContext();
        //private SPSite _site;
        //private TreeNode sourceNode;
        public BaseNode DragedBaseNode;
        ObjectDescriber describer = new ObjectDescriber();
        public static readonly IronPythonEngine ironPythonEngine = new IronPythonEngine();

        private DeserializeDockContent m_deserializeDockContent;

        private Windows.Output m_output;
        private Windows.Properties m_properties;
        private Windows.Log m_log;
        private Windows.Context m_context;
        private Windows.ExplorerView m_explorerView;
        private Windows.GridViewer m_gridviewer;
        private AutoRunScriptsForm m_autoRun;
        private DescriberForm m_describer;

        public static SPCoderForm MainForm;
        FrmSplashScreen splashScreen;
        #endregion

        #region Properties


        #endregion


        public SPCoderForm(FrmSplashScreen splashScreen)
        {
            MainForm = this;
            InitializeComponent();
            this.splashScreen = splashScreen;

            //Load modules (MEF)
            var path = AppDomain.CurrentDomain.BaseDirectory;
            var d = new DirectoryCatalog(path, "*.dll");
            var container = new CompositionContainer(d);
            container.ComposeParts(this);


            //Create all windows
            m_output = new Windows.Output();
            m_properties = new Windows.Properties();
            m_log = new Windows.Log();
            m_context = new Windows.Context();
            m_explorerView = new Windows.ExplorerView();
            m_gridviewer = new Windows.GridViewer();
            m_autoRun = new AutoRunScriptsForm();
            m_describer = new DescriberForm();

            MyContext.Scope = ironPythonEngine.Scope;

            Application.DoEvents();

            m_deserializeDockContent = new DeserializeDockContent(GetContentFromPersistString);
            dockPanel.Skin = new DockPanelSkin();
            //dockPanel.ShowDocumentIcon = false;
            dockPanel.SuspendLayout(true);

            // In order to load layout from XML, we need to close all the DockContents
            CloseAllContents();

            Assembly assembly = Assembly.GetAssembly(typeof(SPCoderForm));
            Stream xmlStream = assembly.GetManifestResourceStream("SPCoder.Resources.DockPanel.xml");
            dockPanel.LoadFromXml(xmlStream, m_deserializeDockContent);
            xmlStream.Close();

            dockPanel.ResumeLayout(true, true);
            Application.DoEvents();

            m_context.AddToContext(new ContextItem { Data = m_output.RtOutput, Name = "rtTxt", Type = m_output.RtOutput.GetType().ToString() });
            m_context.AddToContext(new ContextItem { Data = m_log, Name = "spLog", Type = typeof(ISPCoderLog).ToString() });
            //AddItemToContext(new ContextItem { Data = describer, Name = "describer", Type = describer.GetType().ToString() });
            m_context.AddToContext(new ContextItem { Data = this, Name = "main", Type = this.GetType().ToString() });

        }

        [ImportMany]
        public List<ModuleDescription> Modules { get; set; }

        private IDockContent GetContentFromPersistString(string persistString)
        {            
            if (persistString == typeof(Windows.Properties).ToString())
                return m_properties;
            else if (persistString == typeof(Windows.Context).ToString())
                return m_context;
            else if (persistString == typeof(Output).ToString())
                return m_output;
            else if (persistString == typeof(Log).ToString())
                return m_log;
            else if (persistString == typeof(AutoRunScriptsForm).ToString())
                return m_autoRun;      
            else if (persistString == typeof(DescriberForm).ToString())
                return m_describer;
            else if (persistString == typeof(GridViewer).ToString())
                return m_gridviewer;
            else if (persistString == typeof(ExplorerView).ToString())
                return m_explorerView;
            else
            {
                
                string[] parsedStrings = persistString.Split(new char[] { ',' });
                if (parsedStrings.Length != 3)
                    return null;

                if (parsedStrings[0] != typeof(Code).ToString())
                    return null;

                Code myDoc = new Code();
                codeWindows.Add(myDoc);

                if (parsedStrings[1] != string.Empty)
                    myDoc.FileName = parsedStrings[1];
                if (parsedStrings[2] != string.Empty)
                    myDoc.Text = parsedStrings[2];

                return myDoc;
            }
        }

        private void CloseAllContents()
        {
            // Close all other document windows
            CloseAllDocuments();
        }

        private void CloseAllDocuments()
        {
            if (dockPanel.DocumentStyle == DocumentStyle.SystemMdi)
            {
                foreach (Form form in MdiChildren)
                    form.Close();
            }
            else
            {
                for (int index = dockPanel.Contents.Count - 1; index >= 0; index--)
                {
                    if (dockPanel.Contents[index] is IDockContent)
                    {
                        IDockContent content = (IDockContent)dockPanel.Contents[index];
                        content.DockHandler.Close();
                    }
                }
            }
        }

        private IDockContent FindDocument(string text)
        {
            if (dockPanel.DocumentStyle == DocumentStyle.SystemMdi)
            {
                foreach (Form form in MdiChildren)
                    if (form.Text == text)
                        return form as IDockContent;

                return null;
            }
            else
            {
                foreach (IDockContent content in dockPanel.Documents)
                    if (content.DockHandler.TabText == text)
                        return content;

                return null;
            }
        }

  
        private void toolStripButton1_Click(object sender, EventArgs e)
        {            
            Code c = ActiveDocument;
            if (c != null)
            {
                c.ExecuteSelection();
            }            
        }

     
        public void LogException(Exception ex)
        {
            m_log.LogError(ex.Message);
            m_log.LogError(ex.StackTrace);
            m_log.Show(dockPanel);
            //MessageBox.Show("An error has occurred during execution of the script:" + ex.Message);
        }

        public void LogError(string err)
        {
            m_log.LogError(err);            
            m_log.Show(dockPanel);
            //MessageBox.Show("An error has occurred during execution of the script:" + ex.Message);
        }

        public void AppendToLog(string text)
        {            
            m_log.AppendToLog(text);
        }

        public object ExecuteScript(string script)
        {
            try
            {
                object result = ironPythonEngine.Execute(script);
                return result;
            }
            catch (Exception exc)
            {
                throw exc;
            }
        }

        private void AddItemToContext(object item)
        {            
            m_context.AddToContext(item);
        }

        public void AddToContext(object item)
        {
            m_context.AddToContext(item);
        }

        private void Main_Load(object sender, EventArgs e)
        {
            Application.DoEvents();
            Init();
            Application.DoEvents();
            splashScreen.Hide();
        }

        private void Init()
        {
            this.CenterToScreen();

            Application.DoEvents();

            this.BringToFront();            
            
            ExecuteAutorunScripts();
            splashScreen.iskljuciTimer();
        }
        
        public FastColoredTextBox SourceCodeBox
        {
            get
            {
                Form activeMdi = ActiveMdiChild;
                FastColoredTextBox tempsbc = null;
                if (activeMdi != null && activeMdi is Code)
                {
                    foreach (Control cont in activeMdi.Controls)
                    {
                        if (cont is FastColoredTextBox)
                        {
                            tempsbc = (FastColoredTextBox)cont;
                            break;
                        }
                    }
                }
                return tempsbc;
            }
        }

        public Windows.Code ActiveDocument
        {
            get
            {
                Form activeMdi = ActiveMdiChild;
                
                if (activeMdi != null && activeMdi is Code)
                {
                    return activeMdi as Code;
                }
                return null;
            }
        }

        private void ExecuteAutorunScripts()
        {
            try
            {
                List<string> scripts = AutorunScriptUtils.GetAutorunScriptSources();
                foreach (string script in scripts)
                {
                    try
                    {
                        ExecuteScript(script);
                    }
                    catch (Exception ex)
                    {
                        //LogException(ex);
                        AppendToLog(ex.Message); 
                    }
                }
            }
            catch (Exception ex)
            {
                LogException(ex);                
            }
        }

        public bool AllowClose { get; set; }
        private void Main_FormClosing(object sender, FormClosingEventArgs e)
        {
            AllowClose = true;
            //Here try to close all code windows and if any of them is not closed (cancel is pressed) stop closing the app.
            //var forms = codeWindows

            foreach (var c in codeWindows.ToArray())
            {                
                c.Close();
                if (!AllowClose)
                {
                    e.Cancel = true;
                    return;
                }
            }            
        }

        public void RemoveCodeWindow(Code code)
        {
            if (codeWindows.Contains(code))
                codeWindows.Remove(code);
        }

        private void lbContext_KeyPress(object sender, KeyPressEventArgs e)
        {
            //char c = (Char) Keys.Delete;
        }

        private void virToolStripMenuItem_Click(object sender, EventArgs e)
        {
            
        }

        private void contextMenuStrip1_Opening(object sender, System.ComponentModel.CancelEventArgs e)
        {

        }

        private void toolStripButton6_Click(object sender, EventArgs e)
        {
            string name = "New Script " + codeWindows.Count;
            GenerateNewSourceTab(name, "", null);
        }


        List<Code> codeWindows = new List<Code>();
        /// <summary>
        /// Creates the new source tab.
        /// </summary>
        /// <param name="title">Title of the window</param>
        /// <param name="source">Source code</param>
        /// <param name="fullFileName">Full file path</param>
        public void GenerateNewSourceTab(string title, string source, string fullFileName)
        {

            Code newCode = new Code();
            newCode.Source = source;
            newCode.Title = title;
            newCode.FullFileName = fullFileName;
            newCode.FileName = fullFileName;
            newCode.Show(dockPanel, DockState.Document);
            codeWindows.Add(newCode);
        }

        //void Document_ModifiedChanged(object sender, EventArgs e)
        //{
        //    if (sender is SyntaxDocument)
        //    { 
        //        SyntaxDocument doc = (SyntaxDocument)sender;                
        //        SyntaxBoxControl sbc = doc.Tag as SyntaxBoxControl;
        //        if (sbc != null)
        //        { 
        //            TabPage tab = (TabPage)sbc.Parent;
        //            if (!tab.Text.EndsWith("*"))
        //            {
        //                tab.Text = tab.Text + "*";
        //            }
        //        }
        //    }            
        //}

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            OpenFileDialog fd = new OpenFileDialog();
            fd.FileOk += openFileDialog1_FileOk;
            fd.ShowDialog(this);            
        }

        private void openFileDialog1_FileOk(object sender, System.ComponentModel.CancelEventArgs e)
        {
            OpenFileDialog fd = (OpenFileDialog)sender;
            Stream s = fd.OpenFile();
            StreamReader tr = new StreamReader(s);
            string source = tr.ReadToEnd();
            tr.Close();
            string title = fd.SafeFileName;
            string fullFileName = fd.FileName;

            GenerateNewSourceTab(title, source, fullFileName);
        }

        private void toolStripButton4_Click(object sender, EventArgs e)
        {
            var a = ActiveDocument;
            if (a != null)
            {
                a.SaveCurrentCode(true);
            }   
        }

        private void SaveCurrentCode()
        {
            var a = ActiveDocument;
            if (a != null)
            {
                a.SaveCurrentCode(true);
            }            
        }
        private bool SaveCurrentCode(bool forceOverwrite)
        { 
            var a = ActiveDocument;
            if (a != null)
            {
                return a.SaveCurrentCode(forceOverwrite);
            }
            return false;
        }
      
        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            GenerateNewSourceTab("New Script *", "", null);
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog fd = new OpenFileDialog();
            fd.FileOk += openFileDialog1_FileOk;
            fd.ShowDialog(this);      
        }

        private void btnSaveAs_Click(object sender, EventArgs e)
        {
            SaveCurrentCode(false);
        }

        //private void closeToolStripMenuItem_Click(object sender, EventArgs e)
        //{
        //    TabPage tab = sourceTabs.SelectedTab;
        //    if (tab.Text.EndsWith("*"))
        //    {
        //        DialogResult dialog = MessageBox.Show("Do you want to save script before closing?","Save the script",MessageBoxButtons.YesNoCancel,MessageBoxIcon.Question);
        //        if (dialog == DialogResult.Yes)
        //        {
        //            SaveCurrentCode(false);
        //            sourceTabs.TabPages.Remove(tab);
        //        }
        //        else if (dialog == DialogResult.No)
        //        {
        //            sourceTabs.TabPages.Remove(tab);
        //        }
        //        //in case of Cancel just continue.
        //    }
        //    else
        //    {
        //        sourceTabs.TabPages.Remove(tab);
        //    }
        //}

        private void btnSaveAsAutoRunScript_Click(object sender, EventArgs e)
        {
            SaveAsAutorunScript();
        }

        private void SaveAsAutorunScript()
        {
            //First check if this script has been saved.
            bool result = SaveCurrentCode(true);

            if (!result)
            {
                return;
            }
            FastColoredTextBox tempsbc = SourceCodeBox;
            if (tempsbc == null)
            {
                throw new Exception("Cannot find control box control!");
            }
            string tempFileName = tempsbc.Tag.ToString();

            //After saving the script add it as autorun script at the last position, and then open the autorun scripts window
            var currentConfig = AutorunScriptUtils.GetAutorunConfig();
            int order = (currentConfig.AutoRunScripts == null) ? 1 : currentConfig.AutoRunScripts.Count + 1;
            var script = new AutorunScriptConfigItem();
            script.Order = order;
            script.Path = tempFileName;
            script.Title = Path.GetFileName(tempFileName);

            currentConfig.AutoRunScripts.Add(script);
            AutorunScriptUtils.SaveConfig(currentConfig);
            AppendToLog("Added new autorun script");
            
            //AutoRunScriptsForm arsForm = new AutoRunScriptsForm();
            //arsForm.ShowDialog(this);
            m_autoRun.Show(dockPanel);
            m_autoRun.RefreshView();
            
        }

        private void propertiesToolStripMenuItem2_Click(object sender, EventArgs e)
        {

        }

        private void propertiesToolStripMenuItem1_Click(object sender, EventArgs e)
        {

        }

        private void cms2TreeView_Opening(object sender, CancelEventArgs e)
        {

        }

        private void codeWindowToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveCurrentCode(true);
        }

        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveCurrentCode(false);
        }

        private void saveAsAutorunToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveAsAutorunScript();
        }

        private void autorunToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //AutoRunScriptsForm arsForm = new AutoRunScriptsForm();
            //arsForm.ShowDialog(this);
            m_autoRun.Show(dockPanel);
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutBox box = new AboutBox();
            box.ShowDialog(this);
        }

        private void toolStripButton1_Click_1(object sender, EventArgs e)
        {
            var a = ActiveDocument;
            if (a != null)
            {
                a.ExecuteSelection();
            }
        }

        public void Connect(string url)
        {
            m_explorerView.Connect(url);
        }

        public void Connect(string url, string omType, string username, string password)
        {
            m_explorerView.Connect(url, omType, username, password);
        }

        private void toolStripButton3_Click(object sender, EventArgs e)
        {
            m_properties.Show(dockPanel);
        }

        private void toolStripButton5_Click(object sender, EventArgs e)
        {
            m_output.Show(dockPanel);
        }

        private void toolStripButton7_Click(object sender, EventArgs e)
        {
            m_context.Show(dockPanel);
        }

        public void ShowProperties(object obj)
        {
            m_properties.PgEditor.SelectedObject = obj;
            m_properties.Show(dockPanel);
        }

        internal void ClearOutput()
        {
            m_output.RtOutput.Clear();
            //rtOutput.Clear();            
        }

        internal void Describe(ContextItem item)
        {
            m_describer.Describe(item);
            m_describer.Show(dockPanel, DockState.Document);
        }

        private void toolStripButtonDescriber_Click(object sender, EventArgs e)
        {
            //m_describer.DockState = DockState.Document;
            m_describer.Show(dockPanel, DockState.Document);
        }

        private void toolStripButtonAutorun_Click(object sender, EventArgs e)
        {
            m_autoRun.Show(dockPanel);
        }

        public bool ShouldHighlightInvisibleChars() 
        {
            return btInvisibleChars.Checked;
        }

        private void btInvisibleChars_Click(object sender, EventArgs e)
        {
            foreach (Code tab in codeWindows)
            {
                
                tab.HighlightInvisibleChars();
            }
            if (SourceCodeBox != null)
                SourceCodeBox.Invalidate();
        }

        internal void CodeFormClosed(Code code)
        {
            codeWindows.Remove(code);
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {

        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {

        }

        private void btnExplorer_Click(object sender, EventArgs e)
        {
            m_explorerView.Show(dockPanel);
        }

        private void SPCoderForm_FormClosed(object sender, FormClosedEventArgs e)
        {            
            Application.Exit();
        }

        private void btnAbout_Click(object sender, EventArgs e)
        {
            AboutBox box = new AboutBox();
            box.ShowDialog(this);
        }

        private void btnViewer_Click(object sender, EventArgs e)
        {
            m_gridviewer.Show(dockPanel, DockState.Document);
        }
    }
}